#ifdef __cplusplus
extern "C"{
#endif
#include "xs_def.h"
#include "xs_timer.h"
#include "xs_log.h"
#include "xs_string.h"
#include "xs_linux.h"

struct itimerval 		TimerVal;

const long			dwDiv = 1000;
static long 			g_dwTimeTickCout; 

static xs_pthread_mutex_t TmrMutexVal = PTHREAD_MUTEX_INITIALIZER;

static xs_pthread_mutex_t Ticklock = PTHREAD_MUTEX_INITIALIZER;

unsigned short 		g_dwSysOldTicks;	
unsigned short 		g_dwSysCurTicks;	

TSYS_TIMER_MA  		g_tSysTimerTable; 
TSYS_TIMER_NODE  	g_atSysTimerNode[SYS_MAX_TIMER_NUM];

int xs_timer_init(void)
{
	int byI = 0;		

	g_dwSysOldTicks = 0;		
	
	xs_pthread_mutex_lock(&TmrMutexVal);
	xs_memset(g_atSysTimerNode, 0, sizeof(g_atSysTimerNode));

	for (byI = 0; byI < SYS_MAX_TIMER_NUM; byI++) 
	{
		g_atSysTimerNode[byI].timer_id = byI;
		
		if ((SYS_MAX_TIMER_NUM - 1) == byI) 
			g_atSysTimerNode[byI].ptNext = NULL;
		else
			g_atSysTimerNode[byI].ptNext = (TSYS_TIMER_NODE *)&g_atSysTimerNode[byI + 1];
	}
	
	g_tSysTimerTable.byIdleNum = SYS_MAX_TIMER_NUM;
	g_tSysTimerTable.byUseNum = 0;
	g_tSysTimerTable.ptTimerIdle = (TSYS_TIMER_NODE *)g_atSysTimerNode;
	g_tSysTimerTable.ptTimerUse = NULL;

	xs_pthread_mutex_unlock(&TmrMutexVal);

	return (0);
}

int xs_timer_create(int module_id, ETIMER_TYPE timer_type)
{
        TSYS_TIMER_NODE  *ptTimer = NULL;

        if (module_id >= ESYS_MODULE_MAX)
        {
                return (ETIMER_PROC_ERR);
        }

        if (0 == g_tSysTimerTable.byIdleNum)
        {
                return (ETIMER_PROC_ERR);
        }
        xs_pthread_mutex_lock(&TmrMutexVal);
        ptTimer = g_tSysTimerTable.ptTimerIdle;

        g_tSysTimerTable.byIdleNum--;
		
        if (0 == g_tSysTimerTable.byIdleNum)
                g_tSysTimerTable.ptTimerIdle = NULL;
        else
                g_tSysTimerTable.ptTimerIdle = ptTimer->ptNext;
      
        g_tSysTimerTable.byUseNum++;
        if (NULL == g_tSysTimerTable.ptTimerUse)
        {
                ptTimer->ptPre = NULL;
                ptTimer->ptNext = NULL;
        }
        else
        {
                ptTimer->ptPre = NULL;
                ptTimer->ptNext = g_tSysTimerTable.ptTimerUse;
                g_tSysTimerTable.ptTimerUse->ptPre = ptTimer;
        }
        g_tSysTimerTable.ptTimerUse = ptTimer;
        xs_pthread_mutex_unlock(&TmrMutexVal);
        ptTimer->module_id = module_id;
        ptTimer->timer_type = timer_type;
        ptTimer->eState = ETIMER_STOP;
        ptTimer->wTickOffset = 0;
        ptTimer->dwTimerLimit = 0;
        ptTimer->pvTimeFunc = NULL;
        ptTimer->argc = 0;
        ptTimer->argv = NULL;
        return (ptTimer->timer_id);

}

int xs_timer_delete(int timer_id)
{
	TSYS_TIMER_NODE  *ptTimer = NULL;	
	TSYS_TIMER_NODE  *ptTimerPre = NULL;
	TSYS_TIMER_NODE  *ptTimerNext = NULL;	

	if (timer_id >= SYS_MAX_TIMER_NUM)
		return (ETIMER_PARA_ERR);

	if (ETIMER_IDLE == g_atSysTimerNode[timer_id].eState)
		return (ETIMER_NO_EXIST);

	if (0 == g_tSysTimerTable.byUseNum)
		return (ETIMER_NO_EXIST);


	ptTimer = (TSYS_TIMER_NODE *)&g_atSysTimerNode[timer_id];
	xs_pthread_mutex_lock(&TmrMutexVal);
	g_tSysTimerTable.byUseNum--;

	if (0 == g_tSysTimerTable.byUseNum)
		g_tSysTimerTable.ptTimerUse = NULL;
	else
	{
		ptTimerPre = ptTimer->ptPre;		
		ptTimerNext= ptTimer->ptNext;	

		if ((NULL != ptTimerPre) && (NULL != ptTimerNext))
		{
			ptTimerPre->ptNext = ptTimerNext;
			ptTimerNext->ptPre = ptTimerPre;
		}
		else if (NULL == ptTimerPre)
		{
			ptTimerNext->ptPre = NULL;
			g_tSysTimerTable.ptTimerUse = ptTimerNext;
		}
		else if (NULL == ptTimerNext)
			ptTimerPre->ptNext = NULL;
		else
			return (ETIMER_PROC_ERR);	
	}
	xs_memset(&g_atSysTimerNode[timer_id], 0, sizeof(TSYS_TIMER_NODE));
	g_atSysTimerNode[timer_id].timer_id = timer_id;		

	if (NULL == g_tSysTimerTable.ptTimerIdle)
		g_tSysTimerTable.ptTimerIdle = ptTimer;
	else
	{
		ptTimer->ptNext = g_tSysTimerTable.ptTimerIdle;
		g_tSysTimerTable.ptTimerIdle = ptTimer;
	}
	
	g_tSysTimerTable.byIdleNum++;
	xs_pthread_mutex_unlock(&TmrMutexVal);

	return (ETIMER_OK);
}

int xs_timer_start(int timer_id, int timer_delay, void *timer_func,int argc,char ** argv)
{
	int  wTickOffset = 0;		
	unsigned int g_dwSysCurTicksTmp=0;

	if (timer_id >= SYS_MAX_TIMER_NUM)
		return (ETIMER_PARA_ERR);
	
	if (NULL == timer_func)
		return (ETIMER_PARA_ERR);

	if (ETIMER_IDLE == g_atSysTimerNode[timer_id].eState)
		return (ETIMER_NO_EXIST);

	wTickOffset = timer_delay/200;
	//wTickOffset = wTickOffset/SYS_TICK_MULTIPLE
	
	xs_pthread_mutex_lock(&Ticklock);
	g_dwSysCurTicksTmp=g_dwSysCurTicks;
	xs_pthread_mutex_unlock(&Ticklock);
	
	xs_pthread_mutex_lock(&TmrMutexVal);
	g_atSysTimerNode[timer_id].eState = ETIMER_START;
	g_atSysTimerNode[timer_id].wTickOffset = wTickOffset;
	g_atSysTimerNode[timer_id].dwTimerLimit = g_dwSysCurTicksTmp + wTickOffset;
	g_atSysTimerNode[timer_id].pvTimeFunc = timer_func;
	g_atSysTimerNode[timer_id].argc = argc;
	g_atSysTimerNode[timer_id].argv = argv;
	xs_pthread_mutex_unlock(&TmrMutexVal);
	
	return (ETIMER_OK);
}
int xs_timer_stop(int timer_id)
{
	if (timer_id >= SYS_MAX_TIMER_NUM)
		return (ETIMER_PARA_ERR);
	
	if (ETIMER_IDLE == g_atSysTimerNode[timer_id].eState)
		return (ETIMER_NO_EXIST);
	
	
	xs_pthread_mutex_lock(&TmrMutexVal);
	g_atSysTimerNode[timer_id].eState = ETIMER_STOP;
	xs_pthread_mutex_unlock(&TmrMutexVal);
	
	return (ETIMER_OK);
}

static void xs_sighandler(long timer_sig)
{
	timer_sig = timer_sig;
	
	TSYS_TIMER_NODE  *ptTimer = NULL;	

	g_dwTimeTickCout++;
	g_dwTimeTickCout = 0 ;

	xs_pthread_mutex_lock(&Ticklock);
	g_dwSysCurTicks++;
	g_dwSysOldTicks = g_dwSysCurTicks;
	xs_pthread_mutex_unlock(&Ticklock);

	xs_pthread_mutex_lock(&TmrMutexVal);
	ptTimer = g_tSysTimerTable.ptTimerUse;	

       while (ptTimer != NULL)
	 {
       	if (ETIMER_START == ptTimer->eState)
		{
              	if (g_dwSysOldTicks >= ptTimer->dwTimerLimit) 
			{
				ptTimer->pvTimeFunc(ptTimer->argc,ptTimer->argv);
				if (ETIMER_ONE == ptTimer->timer_type)
					ptTimer->eState = ETIMER_STOP;
				else
					ptTimer->dwTimerLimit = g_dwSysOldTicks + ptTimer->wTickOffset;
                    }
              }
              ptTimer = ptTimer->ptNext;
        }
       xs_pthread_mutex_unlock(&TmrMutexVal);
}

int xs_timer_getstate(int timer_id)
{
	return g_atSysTimerNode[timer_id].eState;
}
int xs_timer_callback_func(int argc,char** argv)
{
	argc = argc;
	argv = argv;
	return 0;
}

void xs_timer_msleep(int time_msec)
{
	int timer_id;
	
	timer_id = xs_timer_create(1, ETIMER_ONE);
	
	xs_timer_start(timer_id, time_msec, xs_timer_callback_func, 0, NULL);

	while(1)
	{
		if(ETIMER_STOP == xs_timer_getstate(timer_id))
		{
			xs_timer_delete(timer_id);
			return;
		}
		usleep(1000);
	}
}

void xs_timer_proc(void *pv_para)
{
	pv_para = pv_para;		/*avoid warnning*/

	signal(SIGALRM, (void *)xs_sighandler);
	
	TimerVal.it_interval.tv_sec = 0;/**/
	TimerVal.it_interval.tv_usec = dwDiv*200;
	TimerVal.it_value.tv_sec = 0;
	TimerVal.it_value.tv_usec = dwDiv*200;
	
	setitimer(ITIMER_REAL, &TimerVal, NULL);

	xs_logd("create the timer proc!!!!!\n");

	for( ; ; )
	{
		//wait for kernel 
		sleep(1000);
	}
}


void say_hello(void)
{
    xs_logd("Hello the crule world ");
}
int xs_timer_test(void)
{
    int module = 10;
    int timer_id = 0;

    xs_timer_init();

    timer_id = xs_timer_create(module, ETIMER_LOOP);

    if(ETIMER_PROC_ERR == timer_id)
        xs_logd("Can not create timer");

    xs_timer_start(timer_id, 1000, &say_hello,0, NULL);

    while(1)
    {
        xs_timer_proc(NULL);
    }

    xs_timer_stop(timer_id);
    xs_timer_delete(timer_id);

    return 0;
}


#ifdef __cplusplus
}
#endif

